package client;

import contacts.Contact;
import contacts.ContactHelper;
import org.apache.commons.logging.impl.Log4JLogger;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import server.ElementalHttpServer;
import utils.Logger;

import java.beans.Encoder;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.sql.Time;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import static com.google.common.base.Strings.isNullOrEmpty;
import static java.net.URLEncoder.encode;

public class ChatClient {

  private Runnable serverRunnable;
  public Contact user;
  public static ContactHelper contactHelper;
  private static final int TTL = 3;
  private static final long RESPONSE_WAIT_TIME = 10 * 1000;
  private static org.apache.log4j.Logger log = Logger.getInstance(ChatClient.class.getName());

  public ChatClient() {
    user = new Contact();
    contactHelper = new ContactHelper();
  }

  public void startClientSideServer(final Contact user) throws IOException {
    new Thread(new Runnable() {
      public void run() {
        try {
          Thread t = new ElementalHttpServer.RequestListenerThread(user);
          t.start();
          log.info("SERVER STARTED");
        } catch (IOException ex) {
          System.out.println("Problems on starting server, error: " + ex.getMessage());
        }
      }
    }).start();

  }

  public void commandSelection() throws IOException {
    String line = "";
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    while ((line = br.readLine()) != null) {
      try {
        if (line.startsWith("name")) {
          // register your name
          String name = line.substring("name".length() + 1, line.length());
          findname(name);
        } else if (line.startsWith("message")) {
          sendMessage(line);
        } else if (line.startsWith("asknames")) {
          // get the own list through the server
          sendAskNamesRequestToContacts();
        } else if (line.startsWith("quit") || line.startsWith("exit")) {
          System.out.println("Quit program!");
          System.exit(-1);
        } else if (line.equals("pwd")) {
          System.out.println("Current user name: " + user.getName());
        } else if (line.equals("list")) {
          System.out.println("In your contact list there are:" + listAllContacts());
        } else {
          System.out.println("There is no such command try again");
        }
      } catch (Exception ex) {
        System.out.println("Error on inserting command: " + ex.getMessage());
      }
    }
  }

  private void sendAskNamesRequestToContacts() {
    contactHelper.loadContacts();
    for (Contact contact : contactHelper.getMyContacts()) {
      utils.HttpGet.execute(String.format("http://%s/chat/asknames?ttl=1&extraIp=" + user.getIPAndPort(), contact.getIPAndPort()));
    }
  }

  private void findname(String name) {
    System.out.println("Sending out " + name + " name looking request");

    user.setAlreadyFound(false);
    user.setName(name);
    contactHelper.loadContacts();

    for (Contact contact : contactHelper.getMyContacts()) {
      String contactUrlRequest = String.format("http://%s/chat/findname?name=%s&myip=%s&ttl=%s",
        contact.getIPAndPort(), user.getName(), user.getIPAndPort(), TTL);
      utils.HttpGet.execute(contactUrlRequest);
    }

    Timer timer = new Timer();
    timer.schedule(new RemindTask(), RESPONSE_WAIT_TIME);
  }

  private void sendMessage(String message) throws IOException {
    String recipientAndMessage = message.substring(message.indexOf("message") + "message".length() + 1);
    String recipient = recipientAndMessage.substring(0, recipientAndMessage.indexOf(" "));
    message = recipientAndMessage.substring(recipientAndMessage.indexOf(recipient) + recipient.length(), recipientAndMessage.length());
    Contact contact = null;
    try {
      contactHelper.loadContacts();
      contact = contactHelper.getContact(recipient);
    } catch (Exception e) {
      contact = null;
      System.out.println("Unable to find '" + recipient + "' in your contact list. Sending it to all contacts. " + e);
    }
    System.out.println("Sending message to: " + recipient);
    String messageURI = "http://" + contact.getIPAndPort() + "/chat/sendmessage";
    String parameters = "?myname=" + encode(isNullOrEmpty(user.getName()) ? "nameless" : user.getName()) + "&myip=" + user.getIPAndPort() + "&message=" + encode(message) + "&ttl=3";
    utils.HttpGet.execute(messageURI + parameters);

  }

  private String listAllContacts() {
    contactHelper.loadContacts();
    StringBuilder sb = new StringBuilder();
    sb.append(String.format(" [%d]", contactHelper.getMyContacts().size()));
    for (Contact contact : contactHelper.getMyContacts()) {
      sb.append(" " + contact.getName() + "(" + contact.getIPAndPort() + ")");
    }
    return sb.toString();
  }

  class RemindTask extends TimerTask {

    public void run() {

      if (user.getName() != null) {
        System.out.println("Name registration successful.");
         // We need to send the name to other users also
        ArrayList<Contact> contactListWithoutCurrentUser = new ArrayList<Contact>();
        for (Contact contact : contactHelper.getMyContacts()) {
          if (!contact.getName().equals(user.getName())) {
            contactListWithoutCurrentUser.add(contact);
          }
        }
        utils.HttpGet.forwardSendname(
          contactListWithoutCurrentUser, user.getName(), user.getIPAndPort(), 1);
      }
      this.cancel();
    }
  }

  public static void main(String[] args) {
    ChatClient client = new ChatClient();
    int port;
    String ip;
    try {
      try {
        ip = args[0];
        port = Integer.parseInt(args[1]);

      } catch (Exception e) {
        System.out.println("Check the program arguments, defaulting to port 6666.");
        port = 6666;
        ip = "localhost";
      }
      String filePathAndName = "./contacts/" + ip + "_" + port + ".txt";
      contactHelper.setFilePathAndName(filePathAndName);
      File file = new File(filePathAndName);
      if (!file.exists())
        contactHelper.getFileHelper().createFile(new File(filePathAndName));

      System.out.println(filePathAndName);
      client.user.setIpAndPort(ip + ":" + port);
      client.startClientSideServer(client.user);
      client.commandSelection();

    } catch (Exception ex) {
      System.out.println(
        String.format("Try again inserting arguments (%s)", ex.getMessage()));
    }
  }
}